%{
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "symboltable.h"
#include "version.h"

	void yyerror (char *);
	extern int yylval;
	extern char *yytag;
	extern int yyline;

	struct symbol *global_symbols = 0;
	struct symbol *local_symbols = 0;
	struct symbol *item;
	FILE *datafile;
	FILE *textfile;
	int textoffset = 0;
	int dataoffset = 0;
	int datawords = 0;
	int textwords = 0;
	int could_resolve = 0;
	int offset;
%}
%token ID
%token LT
%token GT
%token NUMBER 
%token SYMBOL
%token TEXT
%token DATA
%token SECTION
%token ACCESS
%token INVALID

%start object
%%
object: symboltable datasection textsection;

symboltable: SYMBOL entries
           | ;
entries: entry entries
       | ;
entry: name number section access 
{
	if ($3 == S_TEXT)
	{
		offset = textoffset;
	}
	else
	{
		offset = dataoffset;
	}
	if ($4 == S_GLOBAL)
	{
		global_symbols = insert (global_symbols, yytag, $2 + offset, $3, $4);
	}
	else
	{
		local_symbols = insert (local_symbols, yytag, $2, $3, $4);
	}
};
name: ID;
section: SECTION {$$ = yylval;}; 
access: ACCESS {$$ = yylval;};

datasection: DATA words
           | ;
words: dataword words
     | ;

textsection: TEXT instructions
           | ;

instructions: instruction instructions
            | ;

instruction: resolved 
{
	textwords ++; 
	if (could_resolve)
	{
		fprintf (textfile, "%x ", $1);
	}
	else
	{
		fprintf (textfile, "<%s>%x ", yytag, $1);
	}
};
resolved: number {could_resolve = 1; $$ = $1;}
        | unresolved {$$ = $1;};

unresolved: lookup number {$$ = $1 | $2;};
lookup: LT name_ref GT {$$ = $2;};

name_ref: ID 
{
	item = lookup_by_name (local_symbols, yytag);
	if (item)
	{
		could_resolve = 1;
		if (item->section == S_TEXT)
		{
			$$ = item->address + textoffset;
		}
		else
		{
			$$ = item->address + dataoffset;
		}
	}
	else
	{
		could_resolve = 0;
		$$ = 0;
	}
};

dataword: NUMBER {datawords ++; fprintf (datafile, "%x ", yylval);};
number: NUMBER {$$ = yylval;};

%%

void yyerror (char *message)
{
	fprintf (stderr, "***link line %d: %s\n", yyline, message);
}

int main (int argc, char **argv)
{
	int version = GAX_VERSION;
	char datafilename [32];
	char textfilename [32];
	char buf [1024];
	int c;
	int arg;
	int fd;
	sprintf (datafilename, "data%d.tmp", getpid ());
	sprintf (textfilename, "text%d.tmp", getpid ());
	datafile = fopen (datafilename, "w+");
	textfile = fopen (textfilename, "w+");
	for (arg = 1; arg < argc; arg ++)
	{
		close (0);
		open (argv [arg], O_RDONLY);
		yyparse ();
		textoffset += textwords;
		textwords = 0;
		dataoffset += datawords; 
		datawords = 0;
		local_symbols = destroy (local_symbols);
	}
	fclose (textfile);
	fclose (datafile);
	printf (".symbol\n");
	print_table (global_symbols);
	fflush (stdout);
	sprintf (buf, ".data\n");
	write (1, buf, strlen (buf));
	fd = open (datafilename, O_RDONLY);
	while (c = read (fd, buf, 1024))
	{
		write (1, buf, c);
	}
	close (fd);
	sprintf (buf, ".text\n");
	write (1, buf, strlen (buf));
	fd = open (textfilename, O_RDONLY);
	while (c = read (fd, buf, 1024))
	{
		write (1, buf, c);
	}
	close (fd);
	unlink (datafilename);
	unlink (textfilename);
	return 0;
}

